import highlight from "highlight.js"
import marked, { Renderer } from "marked";
interface Item {
  level: never,
  anchor: string,
  text: string
};
const tocObj = {
  add: function (text: string, level: number) {
    let anchor = `#toc${level}${++this.index}`;
    this.toc.push({ anchor, level, text });
    return anchor;
  },
  toHTML: function () {
    let levelStack: [] = [];
    let result: string = "";
    const addStartUL: Function = () => {
      result += '<ul class="anchor-ul" id="anchor-fix">';
    };
    const addEndUL = () => {
      result += "</ul>\n";
    };
    const addLI = (anchor: string, text: string) => {
      result += `<li><a class="toc-link" href="#${anchor}>${text}<a></li>\n`;
    };
    this.toc.forEach(function (item: Item) {
      let levelIndex: number = levelStack.indexOf(item.level);
      if (levelIndex === -1) {
        levelStack.unshift(item.level);
        addStartUL();
        addLI(item.anchor, item.text);
      } else if (levelIndex === 0) {
        addLI(item.anchor, item.text);
      } else {
        while (levelIndex--) {
          levelStack.shift();
          addEndUL();
        }
        addLI(item.anchor, item.text);
      }
    });
    while (levelStack.length) {
      levelStack.shift();
      addEndUL();
    }
    this.toc = [];
    this.index = 0;
    return result;
  },
  toc: [],
  index: 0
};
class MarkUtils {
  rendererMD: marked.Renderer;
  constructor() {
    this.rendererMD = new marked.Renderer();
    this.rendererMD.heading = function (text: string, level: 1 | 2 | 3 | 4 | 5 | 6, raw: string): string {
      let anchor = tocObj.add(text, level);
      return `<h${level} id=${anchor}>${text}</h${level}>\n`;
    };
    highlight.configure({ useBR: true });
    marked.setOptions({
      renderer: this.rendererMD,
      headerIds: false,
      gfm: true,
      breaks: false,
      pedantic: false,
      sanitize: false,
      smartLists: true,
      smartypants: false,
      highlight: function (code) {
        return highlight.highlightAuto(code).value;
      }
    });
  }
  async marked(data: any) {
    if (data) {
      let content = await marked(data);
      let toc = tocObj.toHTML();
      return { content, toc };
    } else {
      return null;
    }
  }
}

const markdown = new MarkUtils();
export default markdown;